package com.aliang.shopping.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliang.shopping.common.Result;
import com.aliang.shopping.common.ResultCodeEnum;
import com.aliang.shopping.contact.ResultMsgContact;
import com.aliang.shopping.contact.SqlColumnConstant;
import com.aliang.shopping.exception.DataException;
import com.aliang.shopping.log.annotation.OperateLog;
import com.aliang.shopping.log.enums.OperateType;
import com.aliang.shopping.model.converter.GoodsSpecConverter;
import com.aliang.shopping.model.dto.goodsSpec.GoodsSpecInsertDTO;
import com.aliang.shopping.model.dto.goodsSpec.GoodsSpecUpdateDTO;
import com.aliang.shopping.model.enums.UserTypeEnum;
import com.aliang.shopping.model.po.GoodsSku;
import com.aliang.shopping.model.po.GoodsSpec;
import com.aliang.shopping.model.vo.TreeVO;
import com.aliang.shopping.security.Auth;
import com.aliang.shopping.security.PreventRepeatSubmit;
import com.aliang.shopping.service.GoodsSkuService;
import com.aliang.shopping.service.GoodsSpecService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/goodsSpec")
@AllArgsConstructor
public class GoodsSpecController {

    private final GoodsSpecService goodsSpecService;
    private final GoodsSpecConverter goodsSpecConverter;

    /**
     * 商品规格信息插入
     *
     * @param insertDTO
     * @return
     */
    @PostMapping("/insert")
    @ApiOperation("商品规格信息插入")
    @PreventRepeatSubmit
    @OperateLog(title = "商品规格信息插入", type = OperateType.INSERT)
    @Auth(role = UserTypeEnum.BUSINESS)
    @Transactional
    public Result<String> insertGoodsSpec(@RequestBody GoodsSpecInsertDTO insertDTO) {
        //数据不能为空
        if (StrUtil.isBlank(insertDTO.getSpecName())
                || insertDTO.getGoodsId() == 0
        ) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //数据转化
        GoodsSpec poByInsertDTO = this.goodsSpecConverter.toPoByInsertDTO(insertDTO);
        // 保存数据
        boolean save = this.goodsSpecService.save(poByInsertDTO);
        if (!save) {
            return Result.fail(ResultMsgContact.INSERT_FAIL);
        }
        //如果是新增父级规格，全部要下架该商品的sku信息
        if (ObjectUtil.isNull(poByInsertDTO.getParentId()) || poByInsertDTO.getParentId() == 0) {
            this.goodsSkuService.update(
                    new LambdaUpdateWrapper<GoodsSku>()
                            .set(GoodsSku::getIsSell, SqlColumnConstant.STATUS_FAIL) //设置为下架
                            .eq(GoodsSku::getGoodsId, insertDTO.getGoodsId())
            );
        }
        return Result.ok(ResultMsgContact.INSERT_SUCCESS);
    }

    private final GoodsSkuService goodsSkuService;

    /**
     * 商品规格信息删除
     *
     * @param ids
     * @return
     */
    @DeleteMapping("/del/{goodsId}")
    @ApiOperation("商品规格信息删除")
    @PreventRepeatSubmit
    @OperateLog(title = "商品规格信息删除", type = OperateType.DELETE)
    @Transactional
    @Auth(role = UserTypeEnum.BUSINESS)
    public Result<String> delGoodsSpec(@RequestBody List<Long> ids, @PathVariable("goodsId") Long goodsId) {
        //先判断商品sku是否设置该规格，如果有，先删除sku信息再删除规格信息
        //查询该商品的全部规格信息
        List<GoodsSku> list = this.goodsSkuService.list(
                new LambdaQueryWrapper<GoodsSku>()
                        .select(GoodsSku::getSpecList)
                        .eq(GoodsSku::getGoodsId, goodsId)
        );
        //获取全部规格Id列表
        List<Long> specList = new ArrayList<>();
        if (!list.isEmpty()) {
            //遍历sku信息，获取规格id
            list.forEach(goodsSku -> {
                List<Long> specIds = JSONUtil.toList(goodsSku.getSpecList(), Long.class);
                //添加到规则列表
                specList.addAll(specIds);
            });
        }
        //规格Id不为空，不能删除
        if (specList.contains(goodsId)) {
            throw new DataException(ResultCodeEnum.SPEC_HAS_SKU);
        }
        //删除规格信息
        boolean removeByIds = this.goodsSpecService.removeByIds(ids);
        // 删除失败
        if (!removeByIds) {
            return Result.fail(ResultMsgContact.DELETE_FAIL);
        }
        return Result.ok(ResultMsgContact.DELETE_SUCCESS);
    }

    /**
     * 商品规格信息更改
     *
     * @return
     */
    @PutMapping("/update")
    @ApiOperation("商品规格信息更改")
    @PreventRepeatSubmit
    @OperateLog(title = "商品规格信息更改", type = OperateType.UPDATE)
    @Auth(role = UserTypeEnum.BUSINESS)
    @Transactional
    public Result<String> updateGoodsSpec(@RequestBody GoodsSpecUpdateDTO updateDTO) {
        //数据不能为空
        if (updateDTO.getId() <= 0
                || StrUtil.isBlank(updateDTO.getSpecName())
        ) {
            throw new DataException(ResultCodeEnum.DATA_LACK);
        }
        //转换数据
        GoodsSpec goodsSpec = this.goodsSpecConverter.toPoByUpdateDTO(updateDTO);
        //保存数据
        this.goodsSpecService.updateById(goodsSpec);
        return Result.ok(ResultMsgContact.UPDATE_SUCCESS);
    }


    /**
     * 根据商品Id获取全部商品规格信息
     */
    @GetMapping("/getGoodsSpecAll/{goodsId}")
    @ApiOperation("根据商品Id获取全部商品规格信息")
    public Result<List<TreeVO>> getGoodsSpecAll(@PathVariable("goodsId") Long goodsId) {
        // 根据商品Id查询规格信息
        List<GoodsSpec> list = this.goodsSpecService.list(
                new LambdaQueryWrapper<GoodsSpec>()
                        .eq(GoodsSpec::getGoodsId, goodsId)
        );
        //数据为空，返回空集合
        if (list.isEmpty()) {
            return Result.ok(Collections.emptyList());
        }
        //根据父Id分组数据
        Map<Long, List<GoodsSpec>> listMap = list.stream().collect(Collectors.groupingBy(GoodsSpec::getParentId));
        //获取一级规格
        List<GoodsSpec> goodsSpecs = listMap.get(0L);
        // 转换VO数据
        List<TreeVO> voList = this.goodsSpecConverter.toVoList(goodsSpecs);
        // 获取二级规格
        voList.forEach(treeVO -> {
            if (listMap.containsKey(treeVO.getValue()))
                treeVO.setChildren(this.goodsSpecConverter.toVoList(listMap.get(treeVO.getValue())));
            else treeVO.setChildren(Collections.emptyList());
        });
        //返回数据
        return Result.ok(voList);
    }

    /**
     * 前台根据商品Id获取全部商品规格信息
     */
    @GetMapping("/getGoodsSpecAllWithFront/{goodsId}")
    @ApiOperation("前台根据商品Id获取全部商品规格信息")
    public Result<List<TreeVO>> getGoodsSpecAllWithFront(@PathVariable("goodsId") Long goodsId) {
        // 根据商品id获取sku信息
        List<GoodsSku> skuList = this.goodsSkuService.list(
                new LambdaQueryWrapper<GoodsSku>()
                        .select(GoodsSku::getSpecList)
                        .eq(GoodsSku::getGoodsId, goodsId)
        );
        // 获取唯一规格Id
        Set<Long> specList = new HashSet<>();
        skuList.stream().map(goodsSku ->
                        JSONUtil.toList(goodsSku.getSpecList(), Long.class) // 转换成数据
                )
                .distinct() // 去重
                .forEach(specList::addAll); // 加入set集合
        // 根据规格Id查询字规格和父规格信息
        List<GoodsSpec> list = this.goodsSpecService.list(
                new LambdaQueryWrapper<GoodsSpec>()
                        .eq(GoodsSpec::getGoodsId, goodsId)
                        .and(i -> i
                                .eq(GoodsSpec::getParentId, 0) // 查询父规格
                                .or()
                                .in(GoodsSpec::getId, specList) // 根据规格Id查询字规格
                        )
        );
        //数据为空，返回空集合
        if (list.isEmpty()) {
            return Result.ok(Collections.emptyList());
        }
        //根据父Id分组数据
        Map<Long, List<GoodsSpec>> listMap = list.stream().collect(Collectors.groupingBy(GoodsSpec::getParentId));
        //获取一级规格
        List<GoodsSpec> goodsSpecs = listMap.get(0L);
        // 转换VO数据
        List<TreeVO> voList = this.goodsSpecConverter.toVoList(goodsSpecs);
        // 获取二级规格
        voList.forEach(treeVO -> {
            if (listMap.containsKey(treeVO.getValue()))
                treeVO.setChildren(this.goodsSpecConverter.toVoList(listMap.get(treeVO.getValue())));
            else treeVO.setChildren(Collections.emptyList());
        });
        //返回数据
        return Result.ok(voList);
    }
}
